/*
 *   Copyright (c) 2024 Huawei Device Co., Ltd.
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

import { HvigorLogger } from '@ohos/hvigor'
import { HMRouterPluginConfig } from './HMRouterPluginConfig'
import {
  AnalyzerResultLike,
  HMAnimatorResult,
  HMInterceptorResult,
  HMLifecycleResult,
  HMRouterResult
} from './PluginModel'
import path from 'path'
import fs from 'fs'
import { Analyzer } from './HMRouterAnalyzer'
import Handlebars from 'handlebars'
import { deleteGeneratorFile } from './Index'

const Logger = HvigorLogger.getLogger()

interface templateModel {
  pageUrl: string
  importPath: string
  componentName: string
  dialog: boolean
  generatorViewName: string
}

export class RouterInfo {
  name: string
  pageSourceFile: string
  buildFunction: string
  data: AnalyzerResultLike

  constructor(
    name: string,
    pageSourceFile: string,
    buildFunction: string,
    data: AnalyzerResultLike = {}
  ) {
    this.name = name
    this.pageSourceFile = pageSourceFile
    this.buildFunction = buildFunction
    this.data = data
  }
}

export class HMRouterHvigorPlugin {
  config: HMRouterPluginConfig
  routerMap: RouterInfo[] = []
  private scanFiles: string[] = []
  HMRouterNum: number = 0

  constructor(config: HMRouterPluginConfig) {
    this.config = config
  }

  analyzeAnnotation() {
    const templateModel = {
      pageUrl: '',
      importPath: '',
      componentName: '',
      dialog: false,
      generatorViewName: ''
    }

    this.config.scanDir.forEach(scanDir => {
      const scanPath = `${this.config.modulePath}/${scanDir}`
      this.deepScan(scanPath, '')
    })

    Logger.info(`扫描到${this.scanFiles.length}个文件`, this.scanFiles)

    this.scanFiles.forEach(filePath => {
      if (filePath.endsWith('.ets')) {
        const importPath = path
          .relative(`${this.config.modulePath}/${this.config.builderDir}`, filePath)
          .replaceAll('\\', '/')
          .replaceAll('.ets', '')

        const analyzer = new Analyzer(filePath, this.config)
        analyzer.start()
        for (let [key, value] of analyzer.analyzeResultMap) {
          value.module = this.config.moduleName
          let pageSourceFile = path.relative(this.config.modulePath, filePath).replaceAll('\\', '/')
          this.pushRouterInfo(value, pageSourceFile, importPath, templateModel)
        }
        this.HMRouterNum = 0
      }
    })
  }

  private stringToHashCode(str: string) {
    let hash = 0
    if (str.length === 0) return hash
    for (let i = 0; i < str.length; i++) {
      const char = str.charCodeAt(i)
      hash = (hash << 5) - hash + char
      hash |= 0 // 转换为32位整数
    }
    return hash
  }

  private pushHMRouter(
    value: AnalyzerResultLike,
    importPath: string,
    templateModel: templateModel
  ) {
    let analyzeResult = value as HMRouterResult
    templateModel.pageUrl = analyzeResult.pageUrl as string
    templateModel.importPath = importPath
    templateModel.componentName = analyzeResult.name as string
    templateModel.dialog = !!analyzeResult.dialog
    templateModel.generatorViewName = 'HM' + analyzeResult.name + this.stringToHashCode(analyzeResult.pageUrl!)

    this.routerMap.push(
      new RouterInfo(
        analyzeResult.pageUrl as string,
        `${this.config.builderDir}/${templateModel.generatorViewName}.ets`,
        `${templateModel.componentName}Builder`,
        value
      )
    )

    this.generateBuilder(templateModel)
  }

  private pushRouterInfo(
    value: AnalyzerResultLike,
    pageSourceFile: string,
    importPath: string,
    templateModel: templateModel
  ) {
    switch (value.annotation) {
      case 'HMRouter':
        this.HMRouterNum++
        if (this.HMRouterNum > 1) {
          Logger.error(`errorCode: 40000004, errorMsg: 文件${pageSourceFile}中存在多个HMRouter注解`)
          deleteGeneratorFile(this.config)
          throw new Error(`文件${pageSourceFile}中存在多个HMRouter注解`)
        }
        this.pushHMRouter(value, importPath, templateModel)
        break
      case 'HMAnimator':
        this.routerMap.push(
          new RouterInfo(
            `__animator__${(value as HMAnimatorResult).animatorName}`,
            pageSourceFile,
            '',
            value
          )
        )
        break
      case 'HMInterceptor':
        this.routerMap.push(
          new RouterInfo(
            `__interceptor__${(value as HMInterceptorResult).interceptorName}`,
            pageSourceFile,
            '',
            value
          )
        )
        break
      case 'HMLifecycle':
        this.routerMap.push(
          new RouterInfo(
            `__lifecycle__${(value as HMLifecycleResult).lifecycleName}`,
            pageSourceFile,
            '',
            value
          )
        )
        break
    }
  }

  generateBuilder(templateModel: templateModel) {
    const builderPath = path.resolve(__dirname, '../' + this.config.builderTpl)
    const tpl = fs.readFileSync(builderPath, { encoding: 'utf-8' })
    const template = Handlebars.compile(tpl)
    const output = template(templateModel)
    const routerBuilderDir = `${this.config.modulePath}/${this.config.builderDir}`
    if (!fs.existsSync(routerBuilderDir)) {
      fs.mkdirSync(routerBuilderDir)
    }
    fs.writeFileSync(`${routerBuilderDir}/${templateModel.generatorViewName}.ets`, output, {
      encoding: 'utf-8'
    })
    Logger.info(`Builder ${templateModel.generatorViewName}.ets has been generated in ${routerBuilderDir}`)
  }

  generateRouterMap() {
    let set = new Set<string>()
    this.routerMap.forEach(item => {
      if(set.has(item.name)) {
        Logger.error(`errorCode: 40000001, errorMsg: 重复的pageUrl、拦截器、生命周期、动画--${item.name}`)
        deleteGeneratorFile(this.config)
        throw new Error(`路由${item.name}重复`)
      } else {
        set.add(item.name)
      }
    })
    let routerMap = {
      routerMap: this.routerMap.map(item => {
        if (item.data && item.data.annotation) { 
          delete item.data.annotation
          // @ts-ignore
          item.data = { data: JSON.stringify(item.data) }
        }
        return item
      })
    }

    const jsonOutput = JSON.stringify(routerMap, null, 2)
    const routerMapDir = `${this.config.modulePath}/${this.config.routerMapDir}`
    if (!fs.existsSync(routerMapDir)) {
      fs.mkdirSync(routerMapDir, { recursive: true })
    }
    fs.writeFileSync(`${routerMapDir}/hm_router_map.json`, jsonOutput, { encoding: 'utf-8' })
    Logger.info(`hm_router_map.json has been generated in ${routerMapDir}`)
    return this.routerMap
  }

  private deepScan(scanPath: string, filePath: string) {
    if (fs.lstatSync(`${scanPath + filePath}`).isDirectory()) {
      const files: string[] = fs.readdirSync(`${scanPath}${filePath}`)
      files.forEach(file => {
        this.deepScan(`${scanPath}${filePath}/`, file)
      })
    } else {
      this.scanFiles.push(`${scanPath}${filePath}`)
    }
  }
}
